package track2.linear;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

import track2.context.Config;
import track2.result.Result;

/**
 * Model 1: combine all the features together
 * Model 2: combine all the leaving out feature together
 * Model 3: 
 * @author yijiazha
 *
 */
public class LinearRegression {
	
	/**
	 * Calculate all the mean value to LRFeatures
	 * @return
	 */
	public static LRFeatures calcMeanFeatures(String path){
		LRFeatures features = new LRFeatures();
		double[] qcNum = new double[Config.queryIdSize];//click number
		double[] qtNum = new double[Config.queryIdSize];//total number
		double[] pcNum = new double[Config.purchaseIdSize];
		double[] ptNum = new double[Config.purchaseIdSize];
		double[] tcNum = new double[Config.titleIdSize];
		double[] ttNum = new double[Config.titleIdSize];
		double[] dcNum = new double[Config.descriptionIdSize];
		double[] dtNum = new double[Config.descriptionIdSize];
		double[] ucNum = new double[Config.userIdSize];
		double[] utNum = new double[Config.userIdSize];
		double[] adcNum = new double[Config.adIdSize];
		double[] adtNum = new double[Config.adIdSize];
		double[] adercNum = new double[Config.advertiserIdSize];
		double[] adertNum = new double[Config.advertiserIdSize];
		
		try{
			System.out.println("Begin calcMeanFeatures for each ids....");
			BufferedReader br = new BufferedReader(new FileReader(path));
			String line;
			int lineNum = 0;
			while ((line = br.readLine()) != null){
				if (lineNum % 1000000 == 0)
					System.out.println(lineNum);
				lineNum++;
				String[] paras = line.split("\t");// id seg1|seg2|seg3....
				double click = Double.parseDouble(paras[0]);
				double impression = Double.parseDouble(paras[1]);
				int adID = Integer.parseInt(paras[3]);
				int aderID = Integer.parseInt(paras[4]);
				int queryID = Integer.parseInt(paras[7]);
				int purchaseID = Integer.parseInt(paras[8]);
				int titleID = Integer.parseInt(paras[9]);
				int descriptionID = Integer.parseInt(paras[10]);
				int userID = Integer.parseInt(paras[11]);
				
				adcNum[adID] += click;
				adtNum[adID] += impression;
				adercNum[aderID] += click;
				adertNum[aderID] += impression;
				qcNum[queryID] += click;
				qtNum[queryID] += impression;
				pcNum[purchaseID] += click;
				ptNum[purchaseID] += impression;
				tcNum[titleID] += click;
				ttNum[titleID] += impression;
				dcNum[descriptionID] += click;
				dtNum[descriptionID] += impression;
				ucNum[userID] += click;
				utNum[userID] += impression;

			}
			br.close();
			for (int i = 0; i < Config.queryIdSize; i++)
				if (qtNum[i] != 0) 
					features.pQueryId[i] = qcNum[i] / qtNum[i];
			for (int i = 0; i < Config.purchaseIdSize; i++)
				if (ptNum[i] != 0) 
					features.pPurId[i] = pcNum[i] / ptNum[i];
			for (int i = 0; i < Config.titleIdSize; i++)
				if (ttNum[i] != 0) 
					features.pTitleId[i] = tcNum[i] / ttNum[i];
			for (int i = 0; i < Config.descriptionIdSize; i++)
				if (dtNum[i] != 0)
					features.pDesId[i] = dcNum[i] / dtNum[i];
			for (int i = 0; i < Config.userIdSize; i++)
				if (utNum[i] != 0)
					features.pUserId[i] = ucNum[i] / utNum[i];
			for (int i = 0; i < Config.adIdSize; i++)
				if (adtNum[i] != 0)
					features.pAdId[i] = adcNum[i] / adtNum[i];
			for (int i = 0; i < Config.advertiserIdSize; i++)
				if (adertNum[i] != 0)
					features.pAderId[i] = adercNum[i] / adertNum[i];
			
			System.out.println("calcMeanFeatures ends...");
		}catch(Exception e){
			e.printStackTrace();
		}
		
		return features;
	}
	
	/**
	 * Output a train file with all the features
	 * Y	ad	ader	query	pur	title	des	user
	 * 
	 * @param features
	 * @param trainPath
	 * @param lrTraingPath
	 */
	public static void outputMeanFeatures(LRFeatures features, String trainPath, String lrTraingPath){
		try{
			BufferedReader br = new BufferedReader(new FileReader(
					Config.trainingFilePath));
			BufferedWriter bw = new BufferedWriter(new FileWriter(
					Config.lrTrainFilePath));
			String line;
			int lineNum = 0;
			System.out.println("output training feature for linear regression Begin...");
			while ((line = br.readLine()) != null) {
				if (lineNum % 1000000 == 0)
					System.out.println(lineNum);
				lineNum++;
				String[] paras = line.split("\t");// id seg1|seg2|seg3....
				double click = Double.parseDouble(paras[0]);
				double impression = Double.parseDouble(paras[1]);
				
				int adID = Integer.parseInt(paras[3]);
				int aderID = Integer.parseInt(paras[4]);
				int queryID = Integer.parseInt(paras[7]);
				int purchaseID = Integer.parseInt(paras[8]);
				int titleID = Integer.parseInt(paras[9]);
				int descriptionID = Integer.parseInt(paras[10]);
				int userID = Integer.parseInt(paras[11]);
				
				bw.write(String.valueOf(click/impression));
				bw.write("\t");
				
				if (adID < features.pAdId.length && features.pAdId[adID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pAdId[adID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\t");
				
				if (aderID < features.pAderId.length && features.pAderId[aderID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pAderId[aderID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\t");
				
				if (queryID < features.pQueryId.length && features.pQueryId[queryID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pQueryId[queryID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\t");
				
				if (purchaseID < features.pPurId.length && features.pPurId[purchaseID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pPurId[purchaseID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\t");
				
				if (titleID < features.pTitleId.length && features.pTitleId[titleID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pTitleId[titleID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\t");
				
				if (descriptionID < features.pDesId.length && features.pDesId[descriptionID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pDesId[descriptionID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\t");
				
				if (userID < features.pUserId.length && features.pUserId[userID] != LRFeatures.NOVALUE)
					bw.write(String.valueOf(features.pUserId[userID]));
//				else bw.write("0");
				else bw.write("0.034882");
				bw.write("\n");
			}
			br.close();
			bw.close();
			System.out.println("output training feature for linear regression Finished...");
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public static LRformula trainLinearModel(boolean[] choose){
		LRformula formula = new LRformula();
		double rmse = 0;
		double lastrmse = 0;
		System.out.println("begin training lr...");
		for (int e = 0; (e < Config.lr_minEpoch) || 
				((e < Config.lr_maxEpoch) && (lastrmse > rmse + Config.lr_meanImpr)) ;e++){
			lastrmse = rmse;
			rmse = 0;
			try{
				BufferedReader br = new BufferedReader(new FileReader(Config.lrTrainFilePath));
				String line;
				int lineNum = 0;
				while ((line = br.readLine()) != null){
					if (lineNum % 1000000 == 0)
						System.out.println(lineNum);
					lineNum++;
					String[] paras = line.split("\t");
					double y = Double.parseDouble(paras[0]);
					double adValue = Double.parseDouble(paras[1]);
					double aderValue = Double.parseDouble(paras[2]);
					double qValue = Double.parseDouble(paras[3]);
					double pValue = Double.parseDouble(paras[4]);
					double tValue = Double.parseDouble(paras[5]);
					double dValue = Double.parseDouble(paras[6]);
					double uValue = Double.parseDouble(paras[7]);
					
					double error = y - formula.getProb(choose, adValue, aderValue, qValue, 
							pValue, dValue, uValue, tValue);
					
					if (choose[0]) formula.left += Config.lr_learningRate * (error - 
							Config.lr_regulazationRate * formula.left);
					if (choose[1]) formula.adWeight += Config.lr_learningRate * (error*adValue - 
							Config.lr_regulazationRate * formula.adWeight);
					if (choose[2]) formula.aderWeight += Config.lr_learningRate * (error*aderValue - 
							Config.lr_regulazationRate * formula.aderWeight);
					if (choose[3]) formula.qWeight += Config.lr_learningRate * (error*qValue - 
							Config.lr_regulazationRate * formula.qWeight);
					if (choose[4]) formula.pWeight += Config.lr_learningRate * (error*pValue - 
							Config.lr_regulazationRate * formula.pWeight);
					if (choose[5]) formula.dWeight += Config.lr_learningRate * (error*dValue - 
							Config.lr_regulazationRate * formula.dWeight);
					if (choose[6]) formula.uWeight += Config.lr_learningRate * (error*uValue - 
							Config.lr_regulazationRate * formula.uWeight);
					if (choose[7]) formula.tWeight += Config.lr_learningRate * (error*tValue - 
							Config.lr_regulazationRate * formula.tWeight);
					rmse += error*error;
				}
				rmse = Math.sqrt(rmse/lineNum);
				System.out.println("RMSE: " + rmse);
				br.close();
			}catch(Exception ex){
				ex.printStackTrace();
			}
			System.out.println("end training lr");
		}
		return formula;
	}
	
	public static Result testLinearModel(boolean[] choose, LRFeatures features, LRformula formula, String testFilePath){
		Result result = new Result();
		result.resultScore = new double[Config.testInstanceNum];
		try{
			System.out.println("lr begin test...");
			BufferedReader br = new BufferedReader(new FileReader(testFilePath));
			String line;
			int index = 0;
			while ((line = br.readLine()) != null){
				if (index % 1000000 == 0)
					System.out.println(index);
				String[] paras = line.split("\t");
				int adID = Integer.parseInt(paras[1]);
				int aderID = Integer.parseInt(paras[2]);
				int queryID = Integer.parseInt(paras[5]);
				int purchaseID = Integer.parseInt(paras[6]);
				int titleID = Integer.parseInt(paras[7]);
				int descriptionID = Integer.parseInt(paras[8]);
				int userID = Integer.parseInt(paras[9]);
				
				double adValue = 0.034882;
				double aderValue = 0.034882;
				double qValue = 0.034882;
				double pValue = 0.034882;
				double dValue = 0.034882;
				double uValue = 0.034882;
				double tValue = 0.034882;
				
				if (adID < features.pAdId.length && features.pAdId[adID] != LRFeatures.NOVALUE)
					adValue = features.pAdId[adID];
				
				if (aderID < features.pAderId.length && features.pAderId[aderID] != LRFeatures.NOVALUE)
					aderValue = features.pAderId[aderID];
				
				if (queryID < features.pQueryId.length && features.pQueryId[queryID] != LRFeatures.NOVALUE)
					qValue = features.pQueryId[queryID];
				
				if (purchaseID < features.pPurId.length && features.pPurId[purchaseID] != LRFeatures.NOVALUE)
					pValue = features.pPurId[purchaseID];
				
				if (titleID < features.pTitleId.length && features.pTitleId[titleID] != LRFeatures.NOVALUE)
					tValue = features.pTitleId[titleID];
				
				if (descriptionID < features.pDesId.length && features.pDesId[descriptionID] != LRFeatures.NOVALUE)
					dValue = features.pDesId[descriptionID];
				
				if (userID < features.pUserId.length && features.pUserId[userID] != LRFeatures.NOVALUE)
					uValue = features.pUserId[userID];
				
				result.resultScore[index] = formula.getProb(choose, adValue, aderValue, qValue, 
						pValue, dValue, uValue, tValue);
				index++;
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println("lr end test");
		return result;
	}
}
